package cryptology1

import (
	"os"
	"encoding/pem"
	"crypto/x509"
	"crypto/rsa"
	"crypto/rand"
	"crypto"
	"crypto/sha1"
	"fmt"
)

/**
使用私钥进行数字签名

1. 打开磁盘的私钥文件
2. 将私钥文件中的内容读出
3. 使用pem对数据解码, 得到了pem.Block结构体变量
4. x509将数据解析成私钥结构体 -> 得到了私钥
5. 创建一个哈希对象 -> md5/sha1
6. 给哈希对象添加数据
7. 计算哈希值
8. 使用rsa中的函数对散列值签名
	func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed
	[]byte) (s []byte, err error)
	参数1: rand.Reader
	参数2: 非对称加密的私钥
	参数3: 使用的哈希算法
	crypto.sha1
	crypto.md5
	参数4: 数据计算之后得到的散列值
	返回值:
	- s: 得到的签名数据
	- err: 错误信息
 */
func signName(plainText []byte) []byte{
	//1.对明文进行哈希运算，得到hash值
	// 1. 创建哈希接口对象
	myHash := sha1.New()
	// 2. 添加数据
	myHash.Write(plainText)
	// 3. 计算结果
	res := myHash.Sum(nil)
	//2.取出私钥，对hash值加密
	//1.取出私钥
	file, _ := os.Open("privatekey.pem")
	fileInfo, _ := file.Stat()
	//2.创建缓冲区保存私钥
	bytes := make([]byte, fileInfo.Size())
	//3.读取私钥
	file.Read(bytes)
	//4.PEM 实质上是 Base64 编码的二进制内容，再加上开始和结束行
	block, _ := pem.Decode(bytes)
	pemBytes := block.Bytes
	//5.x509证书，ParsePKIXPublicKey解析一个DER编码的公钥。这些公钥一般在以"BEGIN PUBLIC KEY"出现的PEM块中
	privateKey, _ := x509.ParsePKCS1PrivateKey(pemBytes)
	//签名
	signPKCS1v15, _ := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, res)
	return signPKCS1v15
}
/**
使用公钥进行签名认证

1.打开公钥文件, 将文件内容读出 - []byte
2. 使用pem解码 -> 得到pem.Block结构体变量
3. 使用x509对pem.Block中的Bytes变量中的数据进行解析 -> 得到一接口
4. 进行类型断言 -> 得到了公钥结构体
5. 对原始消息进行哈希运算(和签名使用的哈希算法一致) -> 散列值
	1. 创建哈希接口
	2. 添加数据
	3. 哈希运算
6. 签名认证 - rsa中的函数
	func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig
	[]byte) (err error)
	参数1: 公钥
	参数2: 哈希算法 -> 与签名使用的哈希算法一致
	参数3: 将原始数据进行哈希原始得到的散列值
	参数4: 签名的字符串
	返回值:
	- nil -> 验证成功
	- !=nil -> 失败
 */
func  verifySignName(plainText []byte){
	file, _ := os.Open("publicKey.pem")
	fileInfo, _ := file.Stat()
	//2.创建缓冲区保存公钥
	bytes := make([]byte, fileInfo.Size())
	//3.读取公钥
	file.Read(bytes)
	//4.PEM 实质上是 Base64 编码的二进制内容，再加上开始和结束行
	block, _ := pem.Decode(bytes)
	pemBytes := block.Bytes
	//5.x509证书，ParsePKIXPublicKey解析一个DER编码的公钥。这些公钥一般在以"BEGIN PUBLIC KEY"出现的PEM块中
	publicKey, _ := x509.ParsePKIXPublicKey(pemBytes)
	pubKey := publicKey.(*rsa.PublicKey)

	//1.对明文进行哈希运算，得到hash值
	// 1. 创建哈希接口对象
	myHash := sha1.New()
	// 2. 添加数据
	//src := []byte("我是小崔, 如果我死了, 肯定不是自杀...我是小崔, 如果我死了, 肯定不是自杀...我是小崔, 如果我死了, 肯定不是自杀...我是小崔, 如果我死了, 肯定不是自杀...我是小崔, 如果我死了, 肯定不是自杀...")
	myHash.Write(plainText)
	//myHash.Write(src)
	//myHash.Write(src)
	// 3. 计算结果
	res := myHash.Sum(nil)

	//公钥验签
	e:=rsa.VerifyPKCS1v15(pubKey,crypto.SHA1,res,signName(plainText))
	if e!=nil {
		fmt.Println("签名不合法")
	}else {
		fmt.Println("签名合法")
	}

}

func main() {
	name := signName([]byte("abcdef"))
	verifySignName(name)
}
